﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Infrastructure.Cache;
using Infrastructure.Helper;
using Infrastructure.Model.UserAuth;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using UAParser;

namespace Infrastructure.Extensions
{
    /// <summary>
    /// HttpContext 扩展工具集：提供HTTP请求上下文相关的常用操作
    /// （包含身份认证、客户端识别、会话管理等工具方法）
    /// </summary>
    public static class HttpContextExtension
    {
        /// <summary>
        /// 判断当前请求是否为Ajax请求
        /// （检测 X-Requested-With 请求头）
        /// </summary>
        /// <param name="request">HTTP请求对象</param>
        /// <returns>是否是Ajax请求</returns>
        public static bool IsAjaxRequest(this HttpRequest request)
        {
            if (request == null)
                throw new ArgumentNullException(nameof(request));

            // 注意：条件判断重复，可简化为单次判断
            return request.Headers["X-Requested-With"] == "XMLHttpRequest";
        }

        /// <summary>
        /// 获取客户端真实IP地址（处理代理服务器场景）
        /// </summary>
        /// <returns>优先返回 X-Forwarded-For 头中的IP</returns>
        public static string GetClientUserIp(this HttpContext context)
        {
            if (context == null) return "";

            string ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
                ip = context.Connection.RemoteIpAddress?.ToString();

            // 本地调试处理
            if (string.IsNullOrEmpty(ip) || ip.Contains("::1"))
                ip = "127.0.0.1";

            // 处理IPv6映射的IPv4地址
            ip = ip.Replace("::ffff:", "127.0.0.1"); // 注意：此处理可能不准确

            return IsIP(ip) ? ip : "127.0.0.1";
        }

        /// <summary>
        /// 验证字符串是否为合法IPv4地址
        /// </summary>
        /// <param name="ip">待验证的IP字符串</param>
        public static bool IsIP(string ip)
        {
            return Regex.IsMatch(ip,
                @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
        }

        /// <summary>
        /// 从用户声明中获取用户ID（primarysid声明）
        /// </summary>
        public static long GetUId(this HttpContext context)
        {
            var claim = context.User.FindFirst("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid");
            return claim != null ? long.Parse(claim.Value) : 0;
        }

        /// <summary>
        /// 获取当前用户的登录名
        /// </summary>
        public static string GetName(this HttpContext context)
        {
            return context.User?.Identity?.Name;
        }

        /// <summary>
        /// 获取用户的权限区域代码（需已登录）
        /// </summary>
        public static string[] GetUserLocation(this HttpContext context)
        {
            // 从JWT令牌获取登录用户信息
            var user = JwtUtil.GetLoginUser(context,
                App.ServiceProvider.GetService<IDistributedCache>());

            return user?.Locations?.ToArray() ?? Array.Empty<string>();
        }

        /// <summary>
        /// 获取当前登录用户的完整信息
        /// </summary>
        public static LoginUser GetCurrentUserInfo(this HttpContext context)
        {
            return JwtUtil.GetLoginUser(context,
                App.ServiceProvider.GetService<IDistributedCache>());
        }

        /// <summary>
        /// 获取客户端User-Agent信息
        /// </summary>
        public static string GetUserAgent(this HttpContext context)
        {
            return context.Request.Headers["User-Agent"];
        }

        /// <summary>
        /// 获取当前请求的认证令牌（优先从header，其次从cookie）
        /// </summary>
        public static string GetToken(this HttpContext context, IDistributedCache distributedCache)
        {
            // 从自定义头获取
            string token = context.ReadHeader("auth_token");
            if (!string.IsNullOrEmpty(token)) return token;

            // 从Authorization头获取
            string authHeader = context.ReadHeader("Authorization");
            if (string.IsNullOrWhiteSpace(authHeader))
            {
                // 从Cookie获取SessionId
                authHeader = context.ReadCookie("SessionId");
            }

            // 从缓存获取实际token
            return distributedCache.GetString("LoginSession:" + authHeader);
        }

        /// <summary>
        /// 解析客户端设备信息（使用UserAgent解析库）
        /// </summary>
        public static ClientInfo GetClientInfo(this HttpContext context)
        {
            var parser = Parser.GetDefault();
            return parser.Parse(context.GetUserAgent());
        }

        /// <summary>
        /// 获取当前请求的路径
        /// </summary>
        public static string GetRequestUrl(this HttpContext context)
        {
            return context?.Request.Path.Value ?? "";
        }

        /// <summary>
        /// 构建用户声明信息集合
        /// </summary>
        /// <param name="user">登录用户对象</param>
        public static List<Claim> GetClaims(this HttpContext context, LoginUser user)
        {
            var claims = new List<Claim>
        {
            new Claim("primarysid", user.UserId.ToString()),
            new Claim(ClaimTypes.Name, user.UserName),
            new Claim("userdata", JsonConvert.SerializeObject(user)) // 注意：敏感数据风险
        };

            // 添加角色声明
            if (user.GroupIds?.Any() == true)
                claims.Add(new Claim(ClaimTypes.Role, string.Join(",", user.GroupIds)));

            // 添加权限声明
            if (user.Permissions?.Any() == true)
                claims.Add(new Claim("perm", string.Join(",", user.Permissions)));

            return claims;
        }

        /// <summary>
        /// 保存认证信息到Cookie（同步等待存在风险）
        /// </summary>
        public static List<Claim> SaveAuth(this HttpContext context, string userId, string sessionId)
        {
            var claims = new List<Claim>
        {
            new Claim("primarysid", userId),
            new Claim(ClaimTypes.Sid, sessionId)
        };

            var identity = new ClaimsIdentity(claims, "Cookies");

            // 异步方法同步等待（可能导致死锁）
            context.SignInAsync("Cookies", new ClaimsPrincipal(identity), new AuthenticationProperties
            {
                IsPersistent = true,
                AllowRefresh = true,
                ExpiresUtc = DateTimeOffset.Now.AddDays(1)
            }).Wait();

            return claims;
        }

        /// <summary>
        /// 记录用户的会话ID（支持多点登录）
        /// </summary>
        public static void SetLoginUserSessionId(string userId, string sessionId)
        {
            var cache = App.ServiceProvider.GetService<IDistributedCache>();
            var manager = new DistributedCacheManager(cache);

            var sessions = manager.Get<List<string>>($"LoginUserSessionId:{userId}", out bool exists)
                ?? new List<string>();

            if (!sessions.Contains(sessionId))
                sessions.Add(sessionId);

            manager.Set($"LoginUserSessionId:{userId}", sessions, new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = DateTime.Now.AddYears(1)
            });
        }

        /// <summary>
        /// 移除用户的所有会话记录
        /// </summary>
        public static void RemoveLoginUserSessionId(string userId)
        {
            var cache = App.ServiceProvider.GetService<IDistributedCache>();
            var manager = new DistributedCacheManager(cache);

            if (manager.Get<List<string>>($"LoginUserSessionId:{userId}", out bool exists)
                is List<string> sessions)
            {
                foreach (var session in sessions)
                    manager.Remove($"LoginSession:{session}");

                manager.Remove($"LoginUserSessionId:{userId}");
            }
        }

        /// <summary>
        /// 获取用户个性化样式配置
        /// </summary>
        public static string GetCustomeStyle(string key)
        {
            var cache = App.ServiceProvider.GetService<IDistributedCache>();
            return new DistributedCacheManager(cache)
                .Get<string>($"Personalized:{key}", out _);
        }

        /// <summary>
        /// 保存用户个性化样式配置（有效期2年）
        /// </summary>
        public static void SetCustomeStyle(string key, string val)
        {
            var cache = App.ServiceProvider.GetService<IDistributedCache>();
            new DistributedCacheManager(cache).Set(
                $"Personalized:{key}",
                val,
                new DistributedCacheEntryOptions { AbsoluteExpiration = DateTime.Now.AddYears(2) }
            );
        }
    }
}
